﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;
using PinCity.ORM;
using NHibernate.Criterion;

namespace PinCity.Models.Repositories
{
    /// <summary>
    /// Basic class, that declares methods for operating on
    /// entities. Any operations with entities should be executed
    /// through this interface. This is the part of "Repository" pattern. 
    /// </summary>
    /// <typeparam name="T">A class, that derives from Entity.</typeparam>
    public abstract class Repository<T> : IRepository<T>
        where T : Models.Base.Entity
    {
        /// <summary>
        /// Initialize repository, fill it with predefined data.
        /// </summary>
        public virtual void Initialize()
        { 
        
        }

        /// <summary>
        /// Saves new entity to the repository or updates an existing one.
        /// </summary>
        /// <param name="entity">An entity to save or update.</param>
        public virtual void SaveOrUpdate(T entity)
        {
            ISession session = FluentManager.GetCurrentSession();
            using(ITransaction transaction = session.BeginTransaction())
            {
                session.SaveOrUpdate(entity);
                transaction.Commit();                
            }
        }

        /// <summary>
        /// Deletes an existing entity from repository.
        /// </summary>
        /// <param name="entity">A valid entity to delete.</param>
        public virtual void Delete(T entity)
        {
            ISession session = FluentManager.GetCurrentSession();
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(entity);
                transaction.Commit();
            }
        }

        /// <summary>
        /// Deletes an exsisting entity by its ID.
        /// </summary>
        /// <param name="id">Identifier of existing entity.</param>
        public virtual void Delete(uint id)
        {
            ISession session = FluentManager.GetCurrentSession();
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(this.Get(id));
                transaction.Commit();
            }
        }

        /// <summary>
        /// Get an existing entity from repository, given its ID.
        /// </summary>
        /// <param name="id">An ID of existing entity.</param>
        /// <returns>An entity or null, if none found.</returns>
        public virtual T Get(uint id)
        {
            T result = null;
            ISession session = FluentManager.GetCurrentSession();
            result = session.Get<T>(id);
            return result;
        }

        /// <summary>
        /// Gets all entities from the repository.
        /// </summary>
        /// <returns>IList of entities.</returns>
        public virtual IList<T> GetAll()
        {
            IList<T> result = null;
            ISession session = FluentManager.GetCurrentSession();
            result = session.CreateCriteria<T>().List<T>();
            return result;
        }

        /// <summary>
        /// Gets all entities, satisfying certain condition from the repository.
        /// </summary>
        /// <param name="expression">Condition</param>
        /// <returns>IList of entities.</returns>
        protected IList<T> GetAll(ICriterion expression)
        {
            IList<T> result = null;
            ISession session = FluentManager.GetCurrentSession();
            result = session.CreateCriteria<T>().Add(expression).List<T>();
            return result;
        }

        /// <summary>
        /// Checks, if an entity with such id is persisted
        /// in this repository.
        /// </summary>
        /// <param name="id">ID of entity.</param>
        /// <returns>True, if entity is found.</returns>
        public bool Contains(uint id)
        {
            IList<T> foundEntities = this.GetAll(Expression.Eq("ID", id));
            return  foundEntities != null && foundEntities.Count() > 0;
        }
    }
}